/**
 * Author:yuiop
 * Date:2022/3/23 10:28
 */
package com.devops.shiro.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.model.BaseUser;
import com.devops.admin.model.DOSRoleUserRelation;
import com.devops.admin.model.Pagination;
import com.devops.admin.model.TableResult;
import com.devops.admin.po.DOSBaseUserPo;
import com.devops.admin.po.DOSRolePo;
import com.devops.admin.po.DOSUserPo;
import com.devops.admin.service.DOSRoleUserRelationService;
import com.devops.admin.util.Assert;
import com.devops.admin.vo.DOSPageVo;
import com.devops.shiro.FocusMicroBaseConstants;
import com.devops.shiro.mapper.DOSBaseUserMapper;
import com.devops.shiro.service.DOSBaseUserService;
import com.devops.shiro.util.EntityUtils;
import com.devops.shiro.util.ShiroUtils;
import com.devops.shiro.vm.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service("dosBaseUserServiceImpl")
public class DOSBaseUserServiceImpl extends ServiceImpl<DOSBaseUserMapper, BaseUser> implements DOSBaseUserService {
    @Autowired
    DOSRoleUserRelationService dosRoleUserRelationService;

    @Override
    public BaseUser getBaseUser() {
        return baseMapper.getBaseUser();
    }

    /**
     * 根据姓名模糊查询用户信息
     * @param name
     * @return
     */
    @Override
    public List<BaseUser> getUsersByName(String name) {
        LambdaQueryWrapper<BaseUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(BaseUser::getRealName,name);
        wrapper.last("limit 10");
        return baseMapper.selectList(wrapper);
    }

    /**
     * 分页查询用户
     * @param inputPage
     * @return
     */
    @Override
    public TableResult<DOSBaseUserPo> getPageUsers(DOSUserVM dosUserVM,DOSPageVo inputPage) {

        Page<BaseUser> queryPage = new Page<>(inputPage.getPageNum(),inputPage.getPageSize());
        Page<DOSBaseUserPo> resultPage = baseMapper.getPageUsers(dosUserVM,queryPage);

        Pagination pagination = Pagination.builder().pageNum(resultPage.getCurrent())
                .pageSize(resultPage.getSize()).total(resultPage.getTotal()).build();
        List<DOSBaseUserPo> list = resultPage.getRecords();
        if (CollectionUtil.isEmpty(list) || list.size() < 1){
            return null;
        }
        List<String> userIds = list.stream().map(DOSBaseUserPo::getId).collect(Collectors.toList());
        List<DOSRolePo> rolePos = dosRoleUserRelationService.getRoles(userIds);
        list.forEach(user -> {
            List<DOSRolePo> roles = new ArrayList<>();
            for (DOSRolePo rolePo : rolePos) {
                if (user.getId().equals(rolePo.getUserId())){
                    roles.add(rolePo);
                }
            }
            user.setRoles(roles);
        });
        return TableResult.<DOSBaseUserPo>builder().list(list).pagination(pagination).build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addUser(BaseUserCreateVM userCreateVM) {
        //loginName检查 原则上不允许出现同名账户
        Assert.isTrueMvc(count(Wrappers.<BaseUser>lambdaQuery()
                .eq(BaseUser::getLoginName,userCreateVM.getLoginName())) == 0,"同名账户已存在，请检查数据");
        //Deal Data
        LocalDateTime now = LocalDateTime.now();
        String userId = "system";
        if (ShiroUtils.currentUser() != null) {
            userId = ShiroUtils.currentUser().getId();
        }
        String newUserId = UUID.randomUUID().toString().replace("-","");
        BaseUser baseUser = EntityUtils.vm2Entity(userCreateVM, BaseUser.class,"roleId");
        baseUser.setId(newUserId);
        baseUser.setCreatDate(now);
        baseUser.setCreatUser(userId);
        baseUser.setUpdateDate(now);
        baseUser.setUpdateUser(userId);
        baseUser.setStatus(FocusMicroBaseConstants.UserStatus.NORMAL.getValue());
        baseUser.setUserType(FocusMicroBaseConstants.UserType.CUSTOMIZE.getValue());
        baseUser.setSuperman(false);
        //password处理 userId as salt MD5 加密
        String password = new SimpleHash("md5",baseUser.getPassword(), baseUser.getId(), 2).toString();
        baseUser.setPassword(password);
        //写base_user
        baseMapper.insert(baseUser);
        //写dos_role_user_relation
        List<DOSRoleUserRelation> relations = new ArrayList<>();
        for (Integer roleId : userCreateVM.getRoleIds()) {
            DOSRoleUserRelation dosRoleUserRelation = DOSRoleUserRelation.builder()
                    .userId(newUserId)
                    .roleId(roleId)
                    .build();
            relations.add(dosRoleUserRelation);
        }
            dosRoleUserRelationService.saveBatch(relations);
        return newUserId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUser(String userId) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(user.getSuperman(),"没有删除权限");
        BaseUserVM userVM = dosRoleUserRelationService.getRoleByUserId(userId).get(0);
        if (userVM.getRoleLevel() != null) {
            Assert.isTrue(1 != userVM.getRoleLevel(),"超级管理员无法被删除");
        }

        //更新user表
        int userDelete = baseMapper.deleteById(userId);

        //更新dos_role_user_relation
        LambdaQueryWrapper<DOSRoleUserRelation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DOSRoleUserRelation::getUserId,userId);
        boolean relationDeleteFlag = dosRoleUserRelationService.remove(wrapper);

        return userDelete > 0 && relationDeleteFlag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(BaseUserUpdateVM userUpdateVM) {
        //校验用户是否存在
        BaseUser searchUser = baseMapper.selectById(userUpdateVM.getId());
        Assert.isTrueMvc(searchUser != null && StrUtil.isNotBlank(searchUser.getId()),"用户不存在，请检查参数");
        //Deal Data
        LocalDateTime now = LocalDateTime.now();
        String userId = ShiroUtils.currentUser().getId();
        BaseUser baseUser = EntityUtils.vm2Entity(userUpdateVM, BaseUser.class,"roleId");

        baseUser.setUpdateDate(now);
        baseUser.setUpdateUser(userId);
        if (StrUtil.isNotBlank(userUpdateVM.getPassword())) {
            //password处理 userId as salt MD5 加密
            String password = new SimpleHash("md5",userUpdateVM.getPassword(), baseUser.getId(), 2).toString();
            baseUser.setPassword(password);
        }
        //更新base_user
        int userUpdate = baseMapper.updateById(baseUser);
        //更新dos_role_user_relation
        updateUserRole(userUpdateVM);

        return userUpdate > 0;
    }

    /**
     * @Author heyabo
     * @Description 更新人员的角色信息
     * @Date 09:48 2022/8/29
     * @Param [userUpdateVM, relation]
     **/
    private void updateUserRole(BaseUserUpdateVM userUpdateVM) {
        List<Integer> newRoleIds = userUpdateVM.getRoleIds();
        LambdaQueryWrapper<DOSRoleUserRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSRoleUserRelation::getUserId, userUpdateVM.getId());
        List<DOSRoleUserRelation> dosRoleUserRelations = dosRoleUserRelationService.list(queryWrapper);
        List<Integer> oldRoleIds = dosRoleUserRelations.stream().map(DOSRoleUserRelation::getRoleId).collect(Collectors.toList());
        // 查询新的人员角色id与旧的人员角色id的差集 - 保存新的人员角色id
        List<Integer> saveRoleIds = newRoleIds.stream().filter(id -> !oldRoleIds.contains(id)).collect(Collectors.toList());
        // 查询旧的人员角色id与新的人员角色id的差集 - 删除差集的人员角色id
        List<Integer> deleteRoleIds = oldRoleIds.stream().filter(id -> !newRoleIds.contains(id)).collect(Collectors.toList());
        // 保存新增的人员角色
        if (CollectionUtil.isNotEmpty(saveRoleIds)){
            List<DOSRoleUserRelation> relations = new ArrayList<>();
            for (Integer saveRoleId : saveRoleIds) {
                DOSRoleUserRelation dosRoleUserRelation = DOSRoleUserRelation.builder()
                .userId(userUpdateVM.getId())
                .roleId(saveRoleId)
                .build();
                relations.add(dosRoleUserRelation);
            }
            dosRoleUserRelationService.saveBatch(relations);
        }
        if (CollectionUtil.isNotEmpty(deleteRoleIds)){
            LambdaQueryWrapper<DOSRoleUserRelation> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DOSRoleUserRelation::getUserId,userUpdateVM.getId())
                            .in(DOSRoleUserRelation::getRoleId,deleteRoleIds);
            dosRoleUserRelationService.remove(queryWrapper1);
        }
    }

    @Override
    public DOSBaseUserPo getBaseUserByLoginName(String loginName) {
        List<DOSBaseUserPo> userPos = baseMapper.getUserByLoginName(loginName);
        if (userPos == null || userPos.size() < 1){
            return null;
        }
        DOSBaseUserPo userPo = userPos.get(0);
        List<String> userIds = userPos.stream().map(DOSBaseUserPo::getId).collect(Collectors.toList());
        List<DOSRolePo> rolePos = dosRoleUserRelationService.getRoles(userIds);
        userPo.setRoles(rolePos);


        return userPo;
    }

    @Override
    public Boolean updatePassword(DOSUserUpdatePasswordVM userUpdateVm) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        //对密码进行加密
        String password = new SimpleHash("md5",userUpdateVm.getOldPassword(), user.getId(), 2).toString();
        BaseUser searchUser = baseMapper.selectById(user.getId());
        Assert.isTrue(password.equals(searchUser.getPassword()),"旧密码输入错误，请重新输入");
        searchUser.setPassword(new SimpleHash("md5",userUpdateVm.getNewPassword(), user.getId(), 2).toString());

        return baseMapper.updateById(searchUser)>0;
    }

    @Override
    public Boolean changePassword(DOSUserChangePasswordVM changePassVM) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(user.getAdminRole(),"没有修改密码的权限");
        BaseUser searchUser = baseMapper.selectById(changePassVM.getUserId());
        Assert.isTrue(null!=searchUser,"用户不存在");
        BaseUserVM userVM = dosRoleUserRelationService.getRoleByUserId(changePassVM.getUserId()).get(0);
        Assert.isTrue(null!=userVM,"未查询到被修改用户的角色信息");
        Assert.isTrue(userVM.getRoleLevel() != 1,"被修改密码的用户为超级管理员，无法修改密码");
        searchUser.setPassword(new SimpleHash("md5",changePassVM.getPassword(), changePassVM.getUserId(), 2).toString());

        return baseMapper.updateById(searchUser)>0;
    }

    @Override
    public List<DOSUserPo> getAllUser(Integer projectId) {
        Assert.isTrueMvc(projectId != null && projectId > 0,"projectId不能为空");
        return baseMapper.getAllUser(projectId);
    }

    @Override
    public List<BaseUser> getTechnologyManager() {
        return baseMapper.getTechnologyManager();
    }

    @Override
    public List<DOSBaseUserPo> getUserByApiToken(String apiToken) {
        return baseMapper.getUserByApiToken(apiToken);
    }
}
